home *** CD-ROM | disk | FTP | other *** search
/ Die Speccy' 97 / Die Speccy' 97.iso / amiga_system / the_aminet / comm / bbs / wwbbs31_source.lha / WWBBS / RxSrc / simplerexx.c < prev    next >
C/C++ Source or Header  |  1994-08-16  |  9KB  |  389 lines

  1. /*
  2.  * Simple ARexx interface by Michael Sinz
  3.  *
  4.  * This is a very "Simple" interface to the world of ARexx...
  5.  * For more complex interfaces into ARexx, it is best that you
  6.  * understand the functions that are provided by ARexx.
  7.  * In many cases they are more powerful than what is presented
  8.  * here.
  9.  *
  10.  * This code is fully re-entrant and self-contained other than
  11.  * the use of SysBase/AbsExecBase and the ARexx RVI support
  12.  * library which is also self-contained...
  13.  */
  14.  
  15. #include    <exec/types.h>
  16. #include    <exec/nodes.h>
  17. #include    <exec/lists.h>
  18. #include    <exec/ports.h>
  19. #include    <exec/memory.h>
  20.  
  21. #include    <proto/exec.h>
  22. #include <proto/rexxsyslib.h>
  23.  
  24. #include    <rexx/storage.h>
  25. #include    <rexx/rxslib.h>
  26.  
  27. #include    <string.h>
  28. #include    <ctype.h>
  29.  
  30. /*
  31.  * A structure for the ARexx handler context
  32.  * This is *VERY* *PRIVATE* and should not be touched...
  33.  */
  34. struct    ARexxContext
  35. {
  36. struct    MsgPort    *ARexxPort;    /* The port messages come in at... */
  37. struct    Library    *RexxSysBase;    /* We will hide the library pointer here... */
  38.     long    Outstanding;    /* The count of outstanding ARexx messages... */
  39.     char    PortName[24];    /* The port name goes here... */
  40.     char    ErrorName[28];    /* The name of the <base>.LASTERROR... */
  41.     char    Extension[8];    /* Default file name extension... */
  42. };
  43.  
  44. #define    AREXXCONTEXT    struct ARexxContext *
  45.  
  46. #include    "SimpleRexx.h"
  47.  
  48. /*
  49.  * This function returns the port name of your ARexx port.
  50.  * It will return NULL if there is no ARexx port...
  51.  *
  52.  * This string is *READ ONLY*  You *MUST NOT* modify it...
  53.  */
  54. char *ARexxName(AREXXCONTEXT RexxContext)
  55. {
  56. register    char    *tmp=NULL;
  57.  
  58.     if (RexxContext) tmp=RexxContext->PortName;
  59.     return(tmp);
  60. }
  61.  
  62. /*
  63.  * This function returns the signal mask that the Rexx port is
  64.  * using.  It returns NULL if there is no signal...
  65.  *
  66.  * Use this signal bit in your Wait() loop...
  67.  */
  68. ULONG ARexxSignal(AREXXCONTEXT RexxContext)
  69. {
  70. register    ULONG    tmp=NULL;
  71.  
  72.     if (RexxContext) tmp=1L << (RexxContext->ARexxPort->mp_SigBit);
  73.     return(tmp);
  74. }
  75.  
  76. /*
  77.  * This function returns a structure that contains the commands sent from
  78.  * ARexx...  You will need to parse it and return the structure back
  79.  * so that the memory can be freed...
  80.  *
  81.  * This returns NULL if there was no message...
  82.  */
  83. struct RexxMsg *GetARexxMsg(AREXXCONTEXT RexxContext)
  84. {
  85. register    struct    RexxMsg    *tmp=NULL;
  86. register        short    flag;
  87.  
  88.     if (RexxContext)
  89.         if (tmp=(struct RexxMsg *)GetMsg(RexxContext->ARexxPort))
  90.     {
  91.         if (tmp->rm_Node.mn_Node.ln_Type==NT_REPLYMSG)
  92.         {
  93.             /*
  94.              * If we had sent a command, it would come this way...
  95.              *
  96.              * Since we don't in this simple example, we just throw
  97.              * away anything that looks "strange"
  98.              */
  99.             flag=FALSE;
  100.             if (tmp->rm_Result1) flag=TRUE;
  101.  
  102.             /*
  103.              * Free the arguments and the message...
  104.              */
  105.             DeleteArgstring(tmp->rm_Args[0]);
  106.             DeleteRexxMsg(tmp);
  107.             RexxContext->Outstanding-=1;
  108.  
  109.             /*
  110.              * Return the error if there was one...
  111.              */
  112.             tmp=flag ? REXX_RETURN_ERROR : REXX_RETURN_OK;
  113.         }
  114.     }
  115.     return(tmp);
  116. }
  117.  
  118. /*
  119.  * Use this to return a ARexx message...
  120.  *
  121.  * If you wish to return something, it must be in the RString.
  122.  * If you wish to return an Error, it must be in the Error.
  123.  * If there is an error, the RString is ignored.
  124.  */
  125. void ReplyARexxMsg(AREXXCONTEXT RexxContext,struct RexxMsg *rmsg,
  126.             char *RString,LONG Error)
  127. {
  128.     if (RexxContext) if (rmsg) if (rmsg!=REXX_RETURN_ERROR)
  129.     {
  130.         rmsg->rm_Result2=0;
  131.         if (!(rmsg->rm_Result1=Error))
  132.         {
  133.             /*
  134.              * if you did not have an error we return the string
  135.              */
  136.             if (rmsg->rm_Action & (1L << RXFB_RESULT)) if (RString)
  137.             {
  138.                 rmsg->rm_Result2=(LONG)CreateArgstring(RString,
  139.                             (LONG)strlen(RString));
  140.             }
  141.         }
  142.  
  143.         /*
  144.          * Reply the message to ARexx...
  145.          */
  146.         ReplyMsg((struct Message *)rmsg);
  147.     }
  148. }
  149.  
  150. /*
  151.  * This function will set an error string for the ARexx
  152.  * application in the variable defined as <appname>.LASTERROR
  153.  *
  154.  * Note that this can only happen if there is an ARexx message...
  155.  *
  156.  * This returns TRUE if it worked, FALSE if it did not...
  157.  */
  158. short SetARexxLastError(AREXXCONTEXT RexxContext,struct RexxMsg *rmsg,
  159.             char *ErrorString)
  160. {
  161. register    short    OkFlag=FALSE;
  162.  
  163.     if (RexxContext) if (rmsg) if (CheckRexxMsg((struct Message *) rmsg))
  164.     {
  165.         /*
  166.          * Note that SetRexxVar() has more than just a TRUE/FALSE
  167.          * return code, but for this "basic" case, we just care if
  168.          * it works or not.
  169.          */
  170.         if (!SetRexxVar((struct Message *) rmsg,RexxContext->ErrorName,ErrorString,
  171.                         (long)strlen(ErrorString)))
  172.         {
  173.             OkFlag=TRUE;
  174.         }
  175.     }
  176.     return(OkFlag);
  177. }
  178.  
  179. /*
  180.  * This function will send a string to ARexx...
  181.  *
  182.  * The default host port will be that of your task...
  183.  *
  184.  * If you set StringFile to TRUE, it will set that bit for the message...
  185.  *
  186.  * Returns TRUE if it send the message, FALSE if it did not...
  187.  */
  188. short SendARexxMsg(AREXXCONTEXT RexxContext,char *RString,
  189.             short StringFile)
  190. {
  191. register    struct    MsgPort    *RexxPort;
  192. register    struct    RexxMsg    *rmsg;
  193. register        short    flag=FALSE;
  194.  
  195.     if (RexxContext) if (RString)
  196.     {
  197.         if (rmsg=CreateRexxMsg(RexxContext->ARexxPort,
  198.                     RexxContext->Extension,
  199.                     RexxContext->PortName))
  200.         {
  201.             rmsg->rm_Action=RXCOMM | (StringFile ?
  202.                             (1L << RXFB_STRING):0);
  203.             if (rmsg->rm_Args[0]=CreateArgstring(RString,
  204.                             (LONG)strlen(RString)))
  205.             {
  206.                 /*
  207.                  * We need to find the RexxPort and this needs
  208.                  * to be done in a Forbid()
  209.                  */
  210.                 Forbid();
  211.                 if (RexxPort=FindPort(RXSDIR))
  212.                 {
  213.                     /*
  214.                      * We found the port, so put the
  215.                      * message to ARexx...
  216.                      */
  217.                     PutMsg(RexxPort,(struct Message *)rmsg);
  218.                     RexxContext->Outstanding+=1;
  219.                     flag=TRUE;
  220.                 }
  221.                 else
  222.                 {
  223.                     /*
  224.                      * No port, so clean up...
  225.                      */
  226.                     DeleteArgstring(rmsg->rm_Args[0]);
  227.                     DeleteRexxMsg(rmsg);
  228.                 }
  229.                 Permit();
  230.             }
  231.             else DeleteRexxMsg(rmsg);
  232.         }
  233.     }
  234.     return(flag);
  235. }
  236.  
  237. /*
  238.  * This function closes down the ARexx context that was opened
  239.  * with InitARexx...
  240.  */
  241. void FreeARexx(AREXXCONTEXT RexxContext)
  242. {
  243. register    struct    RexxMsg    *rmsg;
  244.  
  245.     if (RexxContext)
  246.     {
  247.         /*
  248.          * Clear port name so it can't be found...
  249.          */
  250.         RexxContext->PortName[0]='\0';
  251.  
  252.         /*
  253.          * Clean out any outstanding messages we had sent out...
  254.          */
  255.         while (RexxContext->Outstanding)
  256.         {
  257.             WaitPort(RexxContext->ARexxPort);
  258.             while (rmsg=GetARexxMsg(RexxContext))
  259.             {
  260.                 if (rmsg!=REXX_RETURN_ERROR)
  261.                 {
  262.                     /*
  263.                      * Any messages that come now are blown
  264.                      * away...
  265.                      */
  266.                     SetARexxLastError(RexxContext,rmsg,
  267.                                 "99: Port Closed!");
  268.                     ReplyARexxMsg(RexxContext,rmsg,
  269.                             NULL,100);
  270.                 }
  271.             }
  272.         }
  273.  
  274.         /*
  275.          * Clean up the port and delete it...
  276.          */
  277.         if (RexxContext->ARexxPort)
  278.         {
  279.             while (rmsg=GetARexxMsg(RexxContext))
  280.             {
  281.                 /*
  282.                  * Any messages that still are coming in are
  283.                  * "dead"  We just set the LASTERROR and
  284.                  * reply an error of 100...
  285.                  */
  286.                 SetARexxLastError(RexxContext,rmsg,
  287.                             "99: Port Closed!");
  288.                 ReplyARexxMsg(RexxContext,rmsg,NULL,100);
  289.             }
  290.             DeletePort(RexxContext->ARexxPort);
  291.         }
  292.  
  293.         /*
  294.          * Make sure we close the library...
  295.          */
  296.         if (RexxContext->RexxSysBase)
  297.         {
  298.             CloseLibrary(RexxContext->RexxSysBase);
  299.         }
  300.  
  301.         /*
  302.          * Free the memory of the RexxContext
  303.          */
  304.         FreeMem(RexxContext,sizeof(struct ARexxContext));
  305.     }
  306. }
  307.  
  308. /*
  309.  * This routine initializes an ARexx port for your process
  310.  * This should only be done once per process.  You must call it
  311.  * with a valid application name and you must use the handle it
  312.  * returns in all other calls...
  313.  *
  314.  * NOTE:  The AppName should not have spaces in it...
  315.  *        Example AppNames:  "MyWord" or "FastCalc" etc...
  316.  *        The name *MUST* be less that 16 characters...
  317.  *        If it is not, it will be trimmed...
  318.  *        The name will also be UPPER-CASED...
  319.  *
  320.  * NOTE:  The Default file name extension, if NULL will be
  321.  *        "rexx"  (the "." is automatic)
  322.  */
  323. AREXXCONTEXT InitARexx(char *AppName,char *Extension)
  324. {
  325. register    AREXXCONTEXT    RexxContext=NULL;
  326. register    short        loop;
  327. register    short        count;
  328. register    char        *tmp;
  329.  
  330.     if (RexxContext=AllocMem(sizeof(struct ARexxContext),
  331.                     MEMF_PUBLIC|MEMF_CLEAR))
  332.     {
  333.         if (RexxContext->RexxSysBase=OpenLibrary("rexxsyslib.library",
  334.                                 NULL))
  335.         {
  336.             /*
  337.              * Set up the extension...
  338.              */
  339.             if (!Extension) Extension="rexx";
  340.             tmp=RexxContext->Extension;
  341.             for (loop=0;(loop<7)&&(Extension[loop]);loop++)
  342.             {
  343.                 *tmp++=Extension[loop];
  344.             }
  345.             *tmp='\0';
  346.  
  347.             /*
  348.              * Set up a port name...
  349.              */
  350.             tmp=RexxContext->PortName;
  351.             for (loop=0;(loop<16)&&(AppName[loop]);loop++)
  352.             {
  353.                 *tmp++=toupper(AppName[loop]);
  354.             }
  355.             *tmp='\0';
  356.  
  357.             /*
  358.              * Set up the last error RVI name...
  359.              *
  360.              * This is <appname>.LASTERROR
  361.              */
  362.             strcpy(RexxContext->ErrorName,RexxContext->PortName);
  363.             strcat(RexxContext->ErrorName,".LASTERROR");
  364.  
  365.             /* We need to make a unique port name... */
  366.             Forbid();
  367.             for (count=1,RexxContext->ARexxPort=(VOID *)1;
  368.                         RexxContext->ARexxPort;count++)
  369.             {
  370.                 stci_d(tmp,count);
  371.                 RexxContext->ARexxPort=
  372.                         FindPort(RexxContext->PortName);
  373.             }
  374.  
  375.             RexxContext->ARexxPort=CreatePort(
  376.                         RexxContext->PortName,NULL);
  377.             Permit();
  378.         }
  379.  
  380.         if (    (!(RexxContext->RexxSysBase))
  381.              ||    (!(RexxContext->ARexxPort))    )
  382.         {
  383.             FreeARexx(RexxContext);
  384.             RexxContext=NULL;
  385.         }
  386.     }
  387.     return(RexxContext);
  388. }
  389.